﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QProcess>
#include <QShortcut>
#include <QMessageBox>
#include <QFile>
#include <QApplication>
#include <QInputDialog>
#include <QRegularExpression>
#include <QFileDialog>
#include <QKeyEvent>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);


    proc = new QProcess(this);

    proc->setProcessChannelMode(QProcess::MergedChannels);

    connect(proc, SIGNAL(readyReadStandardOutput()), this, SLOT(read_data()));

    // start temu
    QString cmdCd = "cd ../..\n";
    QString cmdRun = "make run\n";
    QByteArray qbarrCmdCd = cmdCd.toLatin1();
    QByteArray qbarrCmdRun = cmdRun.toLatin1();
    char* chCmdCd = qbarrCmdCd.data();
    char* chCmdRun = qbarrCmdRun.data();
    qint64 lenCmdCd = cmdCd.length();
    qint64 lenCmdRun = cmdRun.length();
    proc->start("bash");
    proc->write(chCmdCd, lenCmdCd);
    proc->write(chCmdRun, lenCmdRun);

}

MainWindow::~MainWindow()
{
    proc->close();
    delete proc;
    proc = NULL;

    delete ui;
    ui = NULL;
}


void MainWindow::read_data()
{
    QByteArray bytes = proc->readAll();
    QString msg = QString::fromLocal8Bit(bytes);

    QRegularExpression regExpr_1("r\n\\$zero.");
    QRegularExpression regExpr_2("w\nNO.");
    QRegularExpressionMatch match_1 = regExpr_1.match(msg);
    QRegularExpressionMatch match_2 = regExpr_2.match(msg);

//    qDebug() << msg << endl;
    if(match_1.hasMatch())
    {
        ui->textEdit_2->clear();
        ui->textEdit_2->append(msg);
        ui->textEdit_2->update();
    }
    else if(match_2.hasMatch())
    {
        ui->textEdit_3->clear();
        ui->textEdit_3->append(msg);
        ui->textEdit_3->update();
    }
    else
    {
        ui->textEdit->append(msg);
        ui->textEdit->update();
    }
}


void MainWindow::on_actionRun_Continue_triggered()
{
    QString cmd = "c\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);

}

void MainWindow::on_actionUsage_triggered()
{
    QString cmd = "help\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_actionSingle_Step_triggered()
{
    QString windowTitle = "Single Step";
    QString windowLabel = "Enter the number of steps";
    int stepNum = QInputDialog::getInt(this, windowTitle, windowLabel, 1, 1, 9);

    QString cmd = "si ";
    cmd.append(QString::number(stepNum));
    cmd.append("\n");

    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_actionView_Breakpoints_triggered()
{
    QString cmd = "info w\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_actionAdd_Breakpoint_triggered()
{
    QString windowTitle = "Add Breakpoint";
    QString windowLabel = "Enter the address of the new breakpoint";
    bool ok = false;
    QString input = QInputDialog::getText(this, windowTitle, windowLabel, QLineEdit::Normal, QString(), &ok);
    if(ok)
    {
        QString cmd = "w ";
        cmd.append(input);
        cmd.append("\n");

        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }
}

void MainWindow::on_actionDelete_Breakpoint_triggered()
{
    QString windowTitle = "Delete Breakpoint";
    QString windowLabel = "Enter the number of the breakpoint to be deleted";
    bool ok = false;
    int dwNo = QInputDialog::getInt(this, windowTitle, windowLabel, 0, 0, 31, 1, &ok);
    if(ok)
    {
        QString cmd = "d ";
        cmd.append(QString::number(dwNo));
        cmd.append("\n");

        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }
}

//void MainWindow::on_actionExit_Simulator_triggered()
//{
//    QString cmd = "q\n";
//    QByteArray qbarr = cmd.toLatin1();
//    char* ch = qbarr.data();
//    qint64 len = cmd.length();
//    proc->write(ch, len);
//}

void MainWindow::on_actionReinitialize_Simulator_triggered()
{
    QString windowTitle = "Warning";
    QString windowLabel = "The simulator will restart. Continue?";
    QMessageBox::StandardButton result;
    result = QMessageBox::question(this, windowTitle, windowLabel, QMessageBox::Yes | QMessageBox::No);
    if(result == QMessageBox::Yes)
    {
        QString cmd = "q\nmake run\n";
        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }
}

void MainWindow::on_pushButton_clicked()
{
    QString cmd = "si 1\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_pushButton_2_clicked()
{
    QString cmd = "c\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_pushButton_3_clicked()
{
    QString windowTitle = "Examine Memory";
    QString windowLabel = "Enter the address";
    bool ok = false;
    QString addr = QInputDialog::getText(this, windowTitle, windowLabel, QLineEdit::Normal, QString(), &ok);
    if(ok)
    {
        windowLabel = "Enter the length";
        int lenInput = QInputDialog::getInt(this, windowTitle, windowLabel, 1, 1, 128, 1, &ok);
        if(ok)
        {
            QString cmd = "x ";
            cmd.append(QString::number(lenInput));
            cmd.append(" ");
            cmd.append(addr);
            cmd.append("\n");

            QByteArray qbarr = cmd.toLatin1();
            char* ch = qbarr.data();
            qint64 len = cmd.length();
            proc->write(ch, len);
        }
    }
}

void MainWindow::on_pushButton_4_clicked()
{
    QString windowTitle = "Evaluate Expression";
    QString windowLabel = "Enter the expression";
    bool ok = false;
    QString input = QInputDialog::getText(this, windowTitle, windowLabel, QLineEdit::Normal, QString(), &ok);

    if(ok)
    {
        QString cmd = "p ";
        cmd.append(input);
        cmd.append("\n");

        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }

}

void MainWindow::on_pushButton_5_clicked()
{
    QString cmd = "info r\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

void MainWindow::on_actionLoad_FIle_triggered()
{
    QFileDialog *fd = new QFileDialog(this, "Choose File");

    if(fd->exec() == QFileDialog::Accepted)
    {
        QString windowTitle = "Warning";
        QString windowLabel = "The simulator will restart. Continue?";
        QMessageBox::StandardButton result;
        result = QMessageBox::question(this, windowTitle, windowLabel, QMessageBox::Yes | QMessageBox::No);

        if(result == QMessageBox::Yes)
        {
            QString fileName = fd->selectedFiles()[0];
            fileName = (fileName.split(".").first()).split("/").last();

            QFile makefile("../../mips_sc/src/Makefile.testcase");
            if(makefile.open(QIODevice::WriteOnly | QIODevice::Text))
            {
                QString makefileNewLine = "USER_PROGRAM := ";
                makefileNewLine.append(fileName);
                QByteArray qbarr_1 = makefileNewLine.toLatin1();
                char* ch_1 = qbarr_1.data();
                makefile.write(ch_1);
                makefile.close();
                qDebug() << 1 << endl;
            }

            QString cmd = "q\ncd mips_sc\nmake\ncd ..\nmake run\n";
            QByteArray qbarr = cmd.toLatin1();
            char* ch = qbarr.data();
            qint64 len = cmd.length();
            proc->write(ch, len);
        }
    }
}

void MainWindow::on_pushButton_6_clicked()
{
    QString windowTitle = "Add Breakpoint";
    QString windowLabel = "Enter the address of the new breakpoint";
    bool ok = false;
    QString input = QInputDialog::getText(this, windowTitle, windowLabel, QLineEdit::Normal, QString(), &ok);
    if(ok)
    {
        QString cmd = "w ";
        cmd.append(input);
        cmd.append("\n");

        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }
}

void MainWindow::on_pushButton_7_clicked()
{
    QString windowTitle = "Delete Breakpoint";
    QString windowLabel = "Enter the number of the breakpoint to be deleted";
    bool ok = false;
    int dwNo = QInputDialog::getInt(this, windowTitle, windowLabel, 0, 0, 31, 1, &ok);
    if(ok)
    {
        QString cmd = "d ";
        cmd.append(QString::number(dwNo));
        cmd.append("\n");

        QByteArray qbarr = cmd.toLatin1();
        char* ch = qbarr.data();
        qint64 len = cmd.length();
        proc->write(ch, len);
    }
}

void MainWindow::on_pushButton_8_clicked()
{
    QString cmd = "info w\n";
    QByteArray qbarr = cmd.toLatin1();
    char* ch = qbarr.data();
    qint64 len = cmd.length();
    proc->write(ch, len);
}

//void MainWindow::on_pushButton_9_clicked()
//{
//    QKeyEvent keyPress_1(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
//    QKeyEvent keyPress_2(QEvent::KeyPress, Qt::Key_C, Qt::NoModifier);
//    QKeyEvent keyRelease_1(QEvent::KeyRelease, Qt::Key_Control, Qt::NoModifier);
//    QKeyEvent keyRelease_2(QEvent::KeyRelease, Qt::Key_C, Qt::NoModifier);
//    QApplication::sendEvent(proc, &keyPress_1);
//    QApplication::sendEvent(proc, &keyPress_2);
//    QApplication::sendEvent(proc, &keyRelease_2);
//    QApplication::sendEvent(proc, &keyRelease_1);
//}
